package com.wmb.userservice.aop;


import com.alibaba.fastjson.JSON;
import com.wmb.userservice.model.pojo.OperationLog;
import com.wmb.userservice.utils.BaseContextUtil;
import com.wmb.userservice.utils.IpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.util.Arrays;

/**
 * 自定义切面，实现日志的记录
 */
@Aspect  // 标识这是一个切面类
@Component
@Slf4j
public class AutoFillAspect {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    // 定义最大重试次数
    private static final int MAX_RETRIES = 3;

    /**
     * 定义切入点（Pointcut）
     * 1. 匹配 com.wmb.userservice 包下所有类的所有方法
     * 2. 要求方法上带有 @AutoFill 注解
     */
    @Pointcut("execution(* com.wmb.userservice.*.*.*(..)) && " +
            "@annotation(com.wmb.userservice.aop.AutoFill)")
    public void autoFillPointCut(){}


    /**
     * 前置通知
     * 在目标方法执行前进行公共字段的自动填充
     * 改进： 将update操作使用环绕通知，获取修改前和修改后的数值，并记录日志 todo
     * @param joinPoint 连接点对象，包含目标方法的相关信息
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint){
        log.info("记录日志...");
        // 获取方法签名对象（包含方法信息） -- AI
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        // 获取方法上的AutoFill注解对象 -- AI
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);

        // 获取目标方法的参数数组
        Object[] args = joinPoint.getArgs();

        // 准备填充的数据：当前时间和当前用户ID
        OperationLog operationLog = new OperationLog();
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        Long currentId = BaseContextUtil.getCurrentId();

        // 操作类型
        OperationType operationType = autoFill.value();
        // 操作人
        operationLog.setUserId(currentId);
        // ip地址
        operationLog.setIp(getIp());
        // 操作时间
        operationLog.setGmtCreate(timestamp);

        // 根据操作类型进行不同的字段填充
        if(operationType == OperationType.REGISTER){
            operationLog.setAction(OperationType.REGISTER.toString());
            operationLog.setDetail(Arrays.toString(args));

        } else if(operationType == OperationType.LOGIN) {
            operationLog.setAction(OperationType.LOGIN.toString());
            operationLog.setDetail(Arrays.toString(args));

        }else if(operationType == OperationType.SELECT){
            operationLog.setAction(OperationType.SELECT.toString());
            operationLog.setDetail(Arrays.toString(args));

        }else if(operationType == OperationType.UPDATE){
            operationLog.setAction(OperationType.UPDATE.toString());
            operationLog.setDetail(Arrays.toString(args));

        }
        // 序列化
        String jsonObject = JSON.toJSONString(operationLog);
        // mq发送日志信息
//        rocketMQTemplate.asyncSend("TestTopic", jsonObject, new SendCallback() {
//            @Override
//            public void onSuccess(SendResult sendResult) {
//                log.info("日志发送成功");
//            }
//
//            @Override
//            public void onException(Throwable throwable) {
//                log.info("日志发送失败");
//                rocketMQTemplate.asyncSend("TestTopic", jsonObject, this);
//            }
//        });

        sendWithRetry("TestTopic", jsonObject);
    }

    // 发送消息（封装重试逻辑） -- AI
    public void sendWithRetry(String topic, Object payload) {
        asyncSendWithRetry(topic, payload, 0);
    }

    //AI
    private void asyncSendWithRetry(String topic, Object payload, int retryCount) {
        rocketMQTemplate.asyncSend(topic, payload, new SendCallback() {
            @Override
            public void onSuccess(SendResult sendResult) {
                log.info("消息发送成功, MsgId: {}", sendResult.getMsgId());
            }
            @Override
            public void onException(Throwable e) {
                if (retryCount < MAX_RETRIES) {
                    int nextRetry = retryCount + 1;
                    log.warn("消息发送失败(第{}次重试), 原因: {}", nextRetry, e.getMessage());
                    // 延迟重试（指数退避）
                    long delay = 1000 * (long) Math.pow(2, retryCount); // 1s, 2s, 4s
                    new Thread(() -> {
                        try {
                            Thread.sleep(delay);
                            asyncSendWithRetry(topic, payload, nextRetry);
                        } catch (InterruptedException ex) {
                            Thread.currentThread().interrupt();
                        }
                    }).start();
                } else {
                    log.error("消息发送失败已达最大重试次数({}次), 放弃发送. 消息内容: {}", MAX_RETRIES, payload);
                    // 兜底：持久化到数据库/文件 todo
                }
            }
        });
    }


    // AI生成
    private String getIp(){
        // 获取当前请求的属性，包括HttpServletRequest对象。
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 将请求属性转换为ServletRequestAttributes，以便获取HttpServletRequest对象。
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        // 获取HttpServletRequest对象。
        if (servletRequestAttributes != null) {
            HttpServletRequest request = servletRequestAttributes.getRequest();
            return IpUtil.getIpAddress(request);
        }
        return null;
    }
}